Skip to main content

Frontend System Design Trade-offs: A Comprehensive Guide

Table of Contents​

  1. Introduction
  2. Rendering Strategies
  3. State Management
  4. Data Fetching
  5. Performance Optimization
  6. Component Architecture
  7. Styling Approaches
  8. Routing Architecture
  9. Micro-Frontend Architecture
  10. Security Considerations
  11. Accessibility
  12. Observability
  13. Testing Strategy
  14. Deployment Strategies
  15. Mobile Considerations
  16. Interview Framework

Introduction​

This guide provides a comprehensive overview of frontend system design trade-offs for technical interviews at companies like Google, Amazon, Microsoft, and other tech giants. Each section explores real-world decisions, their implications, and when to apply them.

Key Principle: Every architectural decision is a trade-off. There are no universally "best" solutionsβ€”only appropriate choices for specific contexts.


Rendering Strategies​

CSR vs SSR vs SSG vs ISR​

ApproachProsConsBest Use CasesExample
CSR (Client-Side Rendering)β€’ Simple deployment
β€’ Low server costs
β€’ Rich interactivity
β€’ Easy state management
β€’ Slow First Contentful Paint
β€’ Poor SEO (without workarounds)
β€’ Blank screen on slow networks
β€’ Higher client device load
β€’ Admin dashboards
β€’ Internal tools
β€’ Apps behind auth
β€’ Highly interactive SPAs
Gmail, Notion
SSR (Server-Side Rendering)β€’ Fast First Contentful Paint
β€’ Excellent SEO
β€’ Works without JS
β€’ Fresh data on every request
β€’ Higher server costs
β€’ TTFB dependency
β€’ More complex deployment
β€’ Hydration overhead
β€’ E-commerce product pages
β€’ News sites
β€’ Social media feeds
β€’ Content-heavy apps
Amazon, Twitter
SSG (Static Site Generation)β€’ Fastest possible loads
β€’ CDN-friendly
β€’ Lowest hosting cost
β€’ Best SEO
β€’ Build time scales poorly
β€’ Data can be stale
β€’ Not suitable for personalized content
β€’ Blogs
β€’ Documentation
β€’ Marketing sites
β€’ Landing pages
Vercel docs, Gatsby sites
ISR (Incremental Static Regeneration)β€’ Balance of fresh + fast
β€’ On-demand regeneration
β€’ CDN benefits
β€’ Scales better than SSG
β€’ More complex mental model
β€’ Stale-while-revalidate behavior
β€’ Platform-specific (Next.js)
β€’ Product catalogs
β€’ SEO landing pages
β€’ News sites with updates
E-commerce listings

Decision Framework:

Is data user-specific?
β”œβ”€ Yes β†’ CSR or SSR
β”‚ └─ Need SEO?
β”‚ β”œβ”€ Yes β†’ SSR
β”‚ └─ No β†’ CSR
└─ No β†’ SSG or ISR
└─ Updates frequently?
β”œβ”€ Yes β†’ ISR
└─ No β†’ SSG

Hydration Strategies​

StrategyDescriptionTrade-offUse When
Full HydrationHydrate entire page at onceSimple but slow on large pagesSmall to medium apps
Progressive HydrationHydrate components as neededComplex but faster TTILarge apps with clear priority
Partial Hydration (Islands Architecture)Only hydrate interactive partsBest performance but requires careful planningMixed static/dynamic content
Resumability (Qwik)Zero hydration, resume from HTMLFastest but new paradigmPerformance-critical apps

Key Insight: Hydration is pure overhead. The less you hydrate, the faster your app, but the more complex your architecture.

Streaming SSR​

Pros:

  • Progressive rendering (faster perceived performance)
  • Doesn't block on slow data fetching
  • Better TTFB for complex pages

Cons:

  • More complex error handling
  • Requires React 18+ or similar framework support
  • Can't set HTTP headers after streaming starts

Use when: You have pages with mixed fast/slow data sources (e.g., user profile with slow recommendation feed).


State Management​

Local vs Global State​

ApproachProsConsBest For
Local State (useState, useReducer)β€’ Simple mental model
β€’ No external dependencies
β€’ Predictable performance
β€’ Easy to test
β€’ Hard to share between distant components
β€’ Prop drilling
β€’ Duplication across components
β€’ UI state (modals, forms)
β€’ Component-specific logic
β€’ Temporary data
Context APIβ€’ Built into React
β€’ No extra library
β€’ Good for theme/i18n
β€’ Re-renders all consumers
β€’ Poor performance at scale
β€’ Not designed for frequent updates
β€’ Global config
β€’ Theme/locale
β€’ User authentication status
Reduxβ€’ Predictable state changes
β€’ Time-travel debugging
β€’ Middleware ecosystem
β€’ DevTools
β€’ Boilerplate heavy
β€’ Learning curve
β€’ Over-engineering for simple apps
β€’ Complex business logic
β€’ Apps with many features
β€’ Need for undo/redo
Zustandβ€’ Minimal boilerplate
β€’ Great DX
β€’ Flexible
β€’ Less mature ecosystem
β€’ Fewer DevTools
β€’ Medium apps
β€’ When Redux feels heavy
Jotai/Recoilβ€’ Atomic state
β€’ Minimal re-renders
β€’ Derived state
β€’ Different paradigm
β€’ Smaller community
β€’ Performance-critical apps
β€’ Complex derived state

Server State Management​

LibraryProsConsUse When
React Query / TanStack Queryβ€’ Caching built-in
β€’ Automatic refetching
β€’ Optimistic updates
β€’ DevTools
β€’ Learning curve
β€’ Additional dependency
Default choice for server state
SWRβ€’ Simpler API
β€’ Stale-while-revalidate
β€’ Smaller bundle
β€’ Fewer features than React QuerySimpler apps, Vercel ecosystem
Apollo Client (GraphQL)β€’ GraphQL integration
β€’ Normalized cache
β€’ Real-time subscriptions
β€’ Heavy bundle
β€’ GraphQL-only
β€’ Complex cache
GraphQL apps with complex data
RTK Queryβ€’ Redux integration
β€’ Code generation
β€’ Cache invalidation
β€’ Redux required
β€’ More setup
Already using Redux

Golden Rule:

  • UI state β†’ Local state
  • Server state β†’ React Query/SWR
  • Cross-feature business logic β†’ Redux/Zustand

State Synchronization​

PatternDescriptionTrade-off
Optimistic UpdatesUpdate UI before server confirmsFast UX but requires rollback logic
Pessimistic UpdatesWait for server before updating UISlower UX but simpler logic
Event SourcingStore state changes as eventsComplete history but complex
CQRSSeparate read/write modelsScales well but more infrastructure

Data Fetching​

API Architectural Patterns​

PatternProsConsBest For
RESTβ€’ Simple, well-understood
β€’ HTTP caching friendly
β€’ Stateless
β€’ Wide tooling support
β€’ Over-fetching (get more data than needed)
β€’ Under-fetching (multiple requests needed)
β€’ Versioning challenges
β€’ Public APIs
β€’ Simple CRUD operations
β€’ When HTTP caching is critical
GraphQLβ€’ Request exactly what you need
β€’ Single endpoint
β€’ Strong typing
β€’ Real-time subscriptions
β€’ Complex caching
β€’ Learning curve
β€’ Heavier client bundle
β€’ Potential N+1 queries
β€’ Complex, nested data
β€’ Mobile apps (reduce requests)
β€’ Rapidly changing requirements
tRPCβ€’ End-to-end type safety
β€’ No code generation
β€’ Simple setup
β€’ Backend lock-in (TypeScript/Node)
β€’ Smaller ecosystem
β€’ Not suitable for public APIs
β€’ Full-stack TypeScript apps
β€’ Internal tools
β€’ Monorepos
gRPCβ€’ Extremely fast (binary)
β€’ Built-in streaming
β€’ Strong contracts
β€’ Browser support requires proxy
β€’ Debugging harder
β€’ Overkill for simple apps
β€’ Microservices
β€’ High-performance needs
β€’ Server-to-server

Interview Insight: REST's advantage is HTTP caching infrastructure. GraphQL trades that for precision but requires custom caching solutions.

Caching Strategies​

LayerStrategyProsCons
Browser CacheHTTP headers (Cache-Control, ETag)β€’ Free
β€’ Automatic
β€’ Reduces server load
β€’ Hard to invalidate
β€’ User-specific data risks
β€’ Storage limits
CDN CacheEdge caching (Cloudflare, Fastly)β€’ Massive scale
β€’ Geographic distribution
β€’ DDoS protection
β€’ Stale data
β€’ Purge delays
β€’ Cost at scale
In-Memory CacheReact Query, SWR, Redux cacheβ€’ Instant access
β€’ Full control
β€’ Memory leaks if not managed
β€’ Lost on refresh
Service WorkerProgressive Web App cacheβ€’ Offline support
β€’ Full control
β€’ Background sync
β€’ Complexity
β€’ Debugging harder
β€’ Version management
IndexedDBClient-side databaseβ€’ Large storage
β€’ Structured queries
β€’ Async API complexity
β€’ Browser differences

Cache Invalidation Strategies:

  • Time-based (TTL)
  • Event-based (on mutation)
  • Stale-while-revalidate
  • Cache-aside pattern

Real-time Data​

TechnologyProsConsUse When
WebSocketβ€’ True bidirectional
β€’ Low latency
β€’ Persistent connection
β€’ More complex infrastructure
β€’ Scaling challenges
β€’ Connection management
β€’ Chat apps
β€’ Live dashboards
β€’ Multiplayer games
Server-Sent Events (SSE)β€’ Simpler than WebSocket
β€’ Auto-reconnect
β€’ HTTP/2 friendly
β€’ One-way only
β€’ Limited browser support
β€’ Live feeds
β€’ Notifications
β€’ Stock tickers
Long Pollingβ€’ Works everywhere
β€’ Simple
β€’ Inefficient
β€’ Higher latency
β€’ Legacy browser support
β€’ Fallback option
GraphQL Subscriptionsβ€’ Integrated with queries
β€’ Type-safe
β€’ Requires GraphQL
β€’ WebSocket dependency
β€’ GraphQL apps needing real-time

Performance Optimization​

Bundle Optimization​

TechniqueImpactTrade-offImplementation
Code SplittingReduce initial bundle by 40-70%More network requests, complexityDynamic imports, route-based splitting
Tree ShakingRemove unused code (10-30% reduction)Requires ES modules, build tool configESM exports, sideEffects: false
Minification30-50% size reductionBuild time increaseTerser, esbuild
Compression (Gzip/Brotli)60-80% size reductionServer CPU usageNginx/CDN configuration
Dynamic ImportsLoad code on demandWaterfalls if not carefulReact.lazy(), Next.js dynamic()
Bundle AnalysisIdentify large dependenciesTime investmentwebpack-bundle-analyzer

Bundle Budget Recommendations:

  • Initial JS: < 200KB (gzipped)
  • Total page weight: < 1MB
  • Time to Interactive: < 3.5s (3G)

Runtime Performance​

OptimizationBenefitCostWhen to Apply
Memoization (useMemo, memo)Prevent expensive recalculationsMemory overhead, mental complexityExpensive computations only
useCallbackPrevent prop changesNegligiblePassing callbacks to memoized components
Virtualization (react-window)Render only visible itemsImplementation complexityLists with 100+ items
Debouncing/ThrottlingReduce function callsDelayed responseSearch inputs, scroll handlers
Web WorkersOffload heavy computationCommunication overheadImage processing, data parsing
Concurrent Features (React 18)Non-blocking renderingRequires React 18+Complex UIs with heavy updates

Performance Anti-patterns:

  • Premature optimization (optimize what matters)
  • Over-memoization (everything wrapped in useMemo)
  • Inline object/array creation in render
  • Anonymous functions in JSX (when causing issues)

Network Performance​

StrategyImpactImplementation
Resource Hints (prefetch, preload, dns-prefetch)Reduce perceived latency<link rel="prefetch">
HTTP/2 & HTTP/3Multiplexing, reduced latencyServer/CDN configuration
Image Optimization (WebP, AVIF, lazy loading)50-80% size reductionPicture element, loading="lazy"
Request BatchingReduce waterfallGraphQL, custom batch endpoint
Service Worker CachingOffline support, instant loadsSW registration, cache strategies

Rendering Performance​

Critical Rendering Path Optimization:

MetricTargetStrategy
FCP (First Contentful Paint)< 1.8sInline critical CSS, reduce blocking resources
LCP (Largest Contentful Paint)< 2.5sOptimize images, preload key resources
TTI (Time to Interactive)< 3.8sCode splitting, reduce JavaScript
CLS (Cumulative Layout Shift)< 0.1Reserve space, avoid dynamic content
FID (First Input Delay)< 100msReduce long tasks, use web workers
INP (Interaction to Next Paint)< 200msOptimize event handlers, debounce

Component Architecture​

Component Patterns​

PatternDescriptionProsConsUse Case
Presentational ComponentsPure UI, no business logicReusable, testableMore filesUI libraries, design systems
Container ComponentsHandle data/logic, pass to presentationalSeparation of concernsBoilerplateFeature components
Compound ComponentsMultiple components work togetherFlexible API, control inversionMore complexTabs, Accordion, Select
Render PropsShare code via function propFlexible, composableCallback hell riskAuth, data fetching
Higher-Order ComponentsEnhance components with shared logicReusable logicProps collision, wrapper hellLegacy code, cross-cutting
HooksShare stateful logicComposable, cleanRules of HooksModern React standard
Controlled vs UncontrolledParent controls state vs local stateControlled: full control; Uncontrolled: simplerControlled: more codeForms (controlled), simple inputs (uncontrolled)

Composition vs Inheritance​

Composition (React's recommendation):

// Good: Composition
<Layout>
<Sidebar />
<Content />
</Layout>

Why composition over inheritance:

  • More flexible
  • Easier to understand
  • Avoids tight coupling
  • Better tree shaking

Code Reusability​

LevelStrategyWhen to Extract
FunctionsUtility functionsUsed 3+ times
HooksCustom hooksShared stateful logic
ComponentsReusable UIUsed 2+ times, stable API
LibrariesPublished packagesUsed across projects

YAGNI Principle: Don't extract until you need it in multiple places.


Styling Approaches​

CSS Methodologies​

ApproachProsConsBundle ImpactBest For
Plain CSSβ€’ Fast
β€’ Simple
β€’ No build step
β€’ Global scope
β€’ Naming conflicts
β€’ Hard to delete
SmallestSmall projects
CSS Modulesβ€’ Scoped by default
β€’ Type-safe (with TS)
β€’ No runtime
β€’ Tooling required
β€’ Dynamic styles harder
SmallComponent libraries
Styled-components / Emotionβ€’ Dynamic styling
β€’ Theming
β€’ Co-location
β€’ Runtime cost
β€’ Larger bundle
β€’ SSR complexity
Medium-LargeApps with complex theming
Tailwind CSSβ€’ Fast development
β€’ Consistent design
β€’ Purge removes unused
β€’ Large class names
β€’ HTML clutter
β€’ Learning curve
Small (with purge)Rapid prototyping, design systems
CSS-in-JS (Zero-runtime) (Vanilla Extract, Linaria)β€’ Type-safe
β€’ No runtime cost
β€’ Scoped
β€’ More setup
β€’ Less flexible
SmallPerformance-critical apps
Sass/Lessβ€’ Variables, mixins
β€’ Mature ecosystem
β€’ Extra build step
β€’ Can encourage complexity
SmallTraditional projects

Runtime vs Build-time​

Runtime CSS-in-JS (Styled-components, Emotion):

  • Pros: Maximum flexibility, dynamic theming
  • Cons: ~10-30KB runtime cost, serialization overhead
  • Use when: Heavy theming, runtime style changes

Build-time CSS (Tailwind, CSS Modules, Vanilla Extract):

  • Pros: Zero runtime, smaller bundles
  • Cons: Less dynamic, more build config
  • Use when: Performance is critical

Theming Systems​

ApproachFlexibilityPerformance
CSS VariablesHighBest
Context + CSS-in-JSVery HighModerate
Class swappingLowBest
Theme prop injectionHighPoor (re-renders)

Routing Architecture​

Client vs Server Routing​

TypeProsConsBest For
Client Routing (React Router, Tanstack Router)β€’ Instant transitions
β€’ Preserved state
β€’ Smooth animations
β€’ No full page reload
β€’ Initial SEO challenges
β€’ Deep linking requires setup
β€’ Larger initial bundle
β€’ SPAs
β€’ Apps behind auth
β€’ Interactive dashboards
Server Routing (Traditional MPAs)β€’ SEO friendly
β€’ Simple mental model
β€’ Progressive enhancement
β€’ Smaller JS bundles
β€’ Slower navigation
β€’ Lost state on navigation
β€’ No smooth transitions
β€’ Content sites
β€’ Marketing pages
β€’ E-commerce
Hybrid (Next.js App Router, Remix)β€’ Best of both worlds
β€’ Fast navigation + SEO
β€’ Streaming
β€’ Framework-specific
β€’ More complexity
β€’ Modern web apps (default choice)

Route-based Code Splitting​

Automatic in Next.js/Remix, manual in React Router:

// Lazy load routes
const Dashboard = lazy(() => import('./Dashboard'));

Benefits:

  • Smaller initial bundles
  • Faster first load
  • Load code as needed

Trade-offs:

  • Route transition delay (can be mitigated with prefetch)
  • More complex error handling

Deep Linking​

Challenges:

  • Preserving app state in URLs
  • Handling authentication redirects
  • Shareable links

Solutions:

  • Query parameters for filters
  • Route parameters for resources
  • Hash fragments for scroll position

Micro-Frontend Architecture​

Integration Approaches​

ApproachProsConsUse When
Build-time (NPM packages)β€’ Simple
β€’ Type-safe
β€’ Optimized
β€’ Coordinated releases
β€’ No independent deploy
Shared component library
Runtime (Module Federation)β€’ Independent deploy
β€’ Version flexibility
β€’ Runtime overhead
β€’ Complex debugging
Large orgs, independent teams
iFrameβ€’ Complete isolation
β€’ Tech-agnostic
β€’ Communication overhead
β€’ UX challenges (navigation, styling)
Legacy integration
Web Componentsβ€’ Standards-based
β€’ Framework-agnostic
β€’ Browser support
β€’ Limited state sharing
Shared widgets

Communication Patterns​

PatternUse CaseTrade-off
PropsParent to childSimple but requires direct relationship
Custom EventsCross-micro-frontendLoose coupling but harder to debug
Shared State (Redux, Zustand)Global coordinationTight coupling
URL StateDeep linking, filtersLimited data types

Shared Dependencies​

Problem: Each micro-frontend bundles React, lodash, etc., leading to duplication.

Solutions:

  1. Module Federation (share at runtime)
  2. External dependencies (load from CDN)
  3. Monorepo (coordinate versions)

Trade-off: Sharing dependencies saves bandwidth but couples deployment.


Security Considerations​

Authentication Patterns​

PatternProsConsUse When
JWT in localStorageβ€’ Simple
β€’ Accessible from JS
β€’ Vulnerable to XSS
β€’ No automatic expiry
Simple apps with low risk
JWT in HttpOnly cookieβ€’ Immune to XSS
β€’ Automatic send
β€’ Requires CSRF protection
β€’ Complex CORS
Production apps (recommended)
Session cookieβ€’ Server-side control
β€’ Easy revocation
β€’ Server state
β€’ Scaling challenges
Traditional server-rendered apps
OAuth/OpenID Connectβ€’ Delegated auth
β€’ Standard protocol
β€’ Complex setup
β€’ Third-party dependency
SSO, social login

Data Validation​

LayerPurposeTools
Client-sideUX feedbackZod, Yup, HTML5 validation
Server-sideSecurity (ALWAYS required)Zod, Joi, class-validator
Type-levelDevelopment safetyTypeScript, JSDoc

Golden Rule: Client validation for UX, server validation for security. Never trust client input.

XSS and CSRF Protection​

XSS (Cross-Site Scripting):

  • Sanitize user input (DOMPurify)
  • Use React (auto-escapes by default)
  • Content Security Policy headers
  • Avoid dangerouslySetInnerHTML

CSRF (Cross-Site Request Forgery):

  • CSRF tokens
  • SameSite cookies
  • Double submit cookies
  • Origin header validation

Accessibility​

WCAG Compliance​

LevelRequirementsUse Case
ABasic accessibilityMinimum legal requirement
AAReasonable accommodationsStandard target (most laws)
AAAHighest accessibilitySpecialized applications

Key Principles (POUR):

  • Perceivable: Alt text, captions, contrast
  • Operable: Keyboard navigation, focus management
  • Understandable: Clear language, consistent navigation
  • Robust: Semantic HTML, ARIA when needed

Performance vs Accessibility​

Common Tension:

  • Heavy focus trapping (performance) vs. simple navigation (a11y)
  • Custom controls (design) vs. native controls (a11y)

Solution: Accessible patterns often improve performance:

  • Semantic HTML is lighter than div soup
  • Keyboard navigation reduces JS events
  • Screen reader support improves SEO

Testing Strategies​

ToolWhat it CatchesLimitations
axe-core / Lighthouse30-40% of issuesAutomated only
Keyboard testingFocus management, operabilityManual
Screen reader testing (NVDA, JAWS, VoiceOver)Real user experienceTime-consuming
jest-axeUnit-level a11yLimited context

Observability​

Logging Strategies​

TypeUse CaseCostRetention
Console logsDevelopmentFreeNone
Application logs (Winston, Pino)Errors, eventsLow7-30 days
Structured logs (JSON)Queryable logsLow30-90 days
APM logs (Datadog, New Relic)Production monitoringHigh90+ days

Best Practices:

  • Log levels (error, warn, info, debug)
  • Correlation IDs for request tracing
  • Avoid logging PII
  • Sample high-volume logs

Error Tracking​

ServiceProsCons
Sentryβ€’ Great DX
β€’ Source maps
β€’ Breadcrumbs
β€’ Can be expensive at scale
Rollbarβ€’ Good alerting
β€’ Telemetry
β€’ Less intuitive UI
BugSnagβ€’ Mobile-friendly
β€’ Session tracking
β€’ Smaller ecosystem
LogRocket / FullStoryβ€’ Session replay
β€’ User context
β€’ Privacy concerns
β€’ Expensive

Error Boundaries (React):

  • Prevent entire app crashes
  • Graceful degradation
  • User-friendly error messages

Performance Monitoring​

Real User Monitoring (RUM):

  • Actual user experience
  • Geographic insights
  • Device/browser breakdown

Synthetic Monitoring:

  • Controlled tests
  • Consistent benchmarks
  • Early warning system

Key Metrics to Track:

  • Core Web Vitals (LCP, FID/INP, CLS)
  • Custom business metrics (time to checkout, etc.)
  • Error rates
  • API latency

Testing Strategy​

Testing Pyramid​

        /\
/E2E\ Few (10%)
/------\
/ INT \ Some (30%)
/----------\
/ UNIT \ Many (60%)
/--------------\
LevelQuantitySpeedConfidenceCost to Maintain
UnitManyFast (ms)LowLow
IntegrationSomeMedium (seconds)MediumMedium
E2EFewSlow (minutes)HighHigh

Testing Types​

TypeToolsWhat to TestWhat to Avoid
Unit TestsJest, Vitestβ€’ Pure functions
β€’ Utilities
β€’ Hooks logic
β€’ Implementation details
β€’ UI styling
Integration TestsReact Testing Libraryβ€’ User interactions
β€’ Component integration
β€’ Data flow
β€’ Mocking everything
E2E TestsPlaywright, Cypressβ€’ Critical user paths
β€’ Multi-page flows
β€’ Real backend
β€’ Testing every feature
Visual RegressionChromatic, Percyβ€’ UI consistency
β€’ Responsive design
β€’ Dynamic content
Performance TestsLighthouse CI, WebPageTestβ€’ Load times
β€’ Bundle sizes
β€’ Core Web Vitals
β€’ Micro-optimizations

Test Coverage vs Speed​

Trade-off:

  • High coverage (90%+) = slow CI, maintenance burden
  • Low coverage (30-50%) = faster, but less confidence

Balanced Approach:

  • 70-80% unit test coverage
  • Test critical paths with integration/E2E
  • Avoid testing third-party libraries
  • Test behavior, not implementation

Anti-patterns:

  • Testing implementation details (how) vs behavior (what)
  • 100% coverage dogma
  • Brittle selectors (test-ids preferred)

Deployment Strategies​

Feature Flags​

BenefitImplementationTrade-off
Progressive rollout1% β†’ 10% β†’ 50% β†’ 100%Technical debt if not cleaned
A/B testingRandom user assignmentComplex analytics
Kill switchInstant feature disableCode complexity
Beta featuresOpt-in for specific usersUser segmentation logic

Popular Tools:

  • LaunchDarkly (enterprise)
  • Flagsmith (open source)
  • Unleash (self-hosted)
  • Custom Redis-based solution

Best Practices:

  • Clean up flags after full rollout
  • Use typed flags (TypeScript)
  • Default to safe fallback
  • Monitor flag performance impact

Progressive Rollouts​

StrategyDescriptionRisk LevelUse Case
Canary ReleaseDeploy to small % of servers firstLowBackend changes, API updates
Blue-Green DeploymentFull environment switchMediumMajor releases, database migrations
Rolling DeploymentGradual server-by-server updateLowStandard deploys
Shadow ModeRun new version alongside old (no user impact)Very LowTesting in production

Monitoring During Rollouts:

  • Error rate spikes
  • Performance degradation
  • User complaints/support tickets
  • Business metrics (conversion, engagement)

Rollback Mechanisms​

MechanismSpeedComplexityData Concerns
Feature flag toggleInstantLowNone (code still deployed)
Git revert + redeploy5-15 minLowNone (if stateless)
Blue-green switchInstantHighDatabase schema compatibility
Database rollbackSlowVery HighData loss risk

Golden Rule: Design for forward compatibility. Never break old clients.


Mobile Considerations​

Responsive vs Adaptive​

ApproachHow It WorksProsConsUse Case
Responsive DesignFluid grids, flexible images, CSS media queriesβ€’ One codebase
β€’ Future-proof
β€’ Easier maintenance
β€’ Can be slow on mobile
β€’ Compromise on experience
β€’ Downloads unused assets
Most websites, content-heavy apps
Adaptive DesignDetect device, serve different layouts/bundlesβ€’ Optimized per device
β€’ Faster on mobile
β€’ Device-specific features
β€’ Multiple codebases
β€’ More maintenance
β€’ Detection complexity
Apps with very different mobile UX
Hybrid (Responsive + Adaptive)Responsive base + adaptive enhancementsβ€’ Best of both
β€’ Progressive enhancement
β€’ Most complexLarge-scale applications

Decision Framework:

Same UX across devices?
β”œβ”€ Yes β†’ Responsive
└─ No β†’ Consider Adaptive
└─ Budget for maintenance?
β”œβ”€ Yes β†’ Adaptive
└─ No β†’ Responsive with mobile-first

Mobile-first vs Desktop-first​

ApproachPhilosophyProsCons
Mobile-firstDesign for mobile, enhance for desktopβ€’ Forces prioritization
β€’ Better mobile performance
β€’ Progressive enhancement
β€’ Smaller base bundle
β€’ Desktop might feel basic
β€’ More CSS media queries
Desktop-firstDesign for desktop, simplify for mobileβ€’ Richer desktop experience
β€’ Familiar workflow
β€’ Mobile as afterthought
β€’ Performance issues
β€’ Harder to simplify than enhance

Modern Best Practice: Mobile-first (60-70% of traffic is mobile for most consumer apps)

Mobile-specific Optimizations:

OptimizationImpactImplementation
Touch-friendly targetsBetter UXMin 44x44px tap targets
Reduced animationsBattery, performanceprefers-reduced-motion media query
Image compressionBandwidth savingsWebP/AVIF, responsive images
Offline supportPWA capabilityService Workers
Reduce font sizesPerformanceFont subsetting, system fonts
Lazy load below foldInitial load timeIntersection Observer

Progressive Web Apps​

PWA Capabilities:

FeatureBenefitBrowser SupportImplementation Effort
Add to Home ScreenApp-like iconExcellentLow (manifest.json)
Offline SupportWorks without internetGoodMedium (Service Worker)
Push NotificationsRe-engagementGood (not iOS Safari)Medium (Push API)
Background SyncReliable data syncLimitedHigh
Install PromptsIncrease installsVariableLow

PWA vs Native App Trade-offs:

AspectPWANative AppWinner
Development costLower (one codebase)Higher (iOS + Android)PWA
DistributionNo app storeApp storesPWA (easier)
Device accessLimitedFullNative
PerformanceGoodExcellentNative
UpdatesInstantStore review delayPWA
DiscoverabilitySEOApp store optimizationDepends
Offline capabilityGoodExcellentNative

When to Choose PWA:

  • Content-focused apps
  • Limited budget
  • Need SEO
  • Frequent updates
  • Cross-platform priority

When to Choose Native:

  • Heavy device integration (camera, sensors, etc.)
  • Performance-critical (games, AR/VR)
  • Native UX is important
  • App store presence needed

Hybrid Approach (PWA + Native shell):

  • LinkedIn, Twitter use this
  • PWA for web, native wrapper for app stores
  • Shared web codebase

Interview Framework​

How to Approach Questions​

Step-by-step Framework:

1. Clarify Requirements (5 min)​

Ask questions to understand:

  • Scale: How many users? Geographic distribution?
  • Features: Core vs nice-to-have?
  • Constraints: Timeline? Team size? Budget?
  • Users: Technical level? Devices? Network conditions?
  • Performance: What matters most? (SEO, TTI, offline, etc.)

Example Questions:

  • "How many concurrent users do we expect?"
  • "Is this a public-facing site or internal tool?"
  • "What's more important: initial load time or runtime performance?"
  • "Do we need to support offline functionality?"
  • "What browsers/devices must we support?"

2. Define High-level Architecture (10 min)​

Structure your answer:

1. Rendering strategy (CSR/SSR/SSG)
2. State management approach
3. Data fetching pattern
4. Key infrastructure (CDN, caching)
5. Major trade-offs

Visual representation helps:

[User] β†’ [CDN] β†’ [Next.js SSR] β†’ [API Gateway] β†’ [Services]
↓
[React Query Cache]
↓
[Component Tree]

3. Dive into Components (15 min)​

Pick 2-3 interesting areas to detail:

  • Performance bottlenecks
  • Complex state management
  • Real-time features
  • Security concerns

Show trade-off thinking: "I would start with X because [reason], but if we see Y problem, we could switch to Z."

4. Discuss Trade-offs (5 min)​

For every decision, mention:

  • Why this choice? (requirements it satisfies)
  • What's the downside? (what we're sacrificing)
  • When would we change? (what would make us revisit)

5. Scaling & Evolution (5 min)​

Discuss how the system evolves:

  • "At 10K users: Simple SSR works fine"
  • "At 100K users: Add CDN caching, API rate limiting"
  • "At 1M users: Consider ISR, edge functions, micro-frontends"

Common Pitfalls​

PitfallWhy It's BadFix
Jumping to solutionsMiss requirements, wrong architectureAlways clarify first
Over-engineeringAdds complexity unnecessarilyStart simple, justify complexity
Ignoring trade-offsShows lack of depthEvery decision has pros AND cons
Buzzword droppingSounds hollow without contextExplain WHY you'd use a technology
Not asking questionsSeems overconfident or inexperiencedShow curiosity, clarify ambiguity
Ignoring non-functional requirementsIncomplete designConsider security, a11y, i18n, monitoring
One-size-fits-allDifferent problems need different solutionsAdapt to requirements
Forgetting about usersToo technical, not user-centricConsider UX, accessibility, performance

Sample Answers​

Example 1: Design Instagram Feed​

Clarification Questions:

  • How many users? Daily active users?
  • Real-time updates required?
  • Image upload/processing requirements?
  • Offline support needed?

High-level Design:

Architecture:
β”œβ”€ Rendering: SSR for initial feed (SEO, fast FCP)
β”œβ”€ Client: React SPA after hydration
β”œβ”€ State:
β”‚ β”œβ”€ React Query for feed data
β”‚ └─ Zustand for UI state (modals, selections)
β”œβ”€ Real-time: WebSocket for new posts notification
└─ Media: CDN with progressive image loading

Key Decisions:

  1. Rendering: SSR β†’ CSR hybrid

    • Why: Fast initial load + SEO, then rich client interactivity
    • Trade-off: More complex than pure CSR
    • When to change: If SEO isn't important, go CSR-only
  2. Infinite Scroll with Virtualization

    • Why: Smooth UX for long feeds
    • Implementation: react-window + Intersection Observer
    • Trade-off: Complexity vs. memory efficiency
  3. Optimistic Updates

    • Why: Instant feedback on likes/comments
    • Trade-off: Need rollback logic if server fails
    • Implementation: React Query mutations
  4. Image Strategy

    • Why: Images dominate bandwidth
    • Approach:
      • Lazy load below fold
      • WebP with JPEG fallback
      • Responsive images (srcset)
      • Blur placeholder (LQIP)
  5. Caching Strategy

    • CDN: Cache images (long TTL)
    • React Query: Cache feed data (5 min stale time)
    • Service Worker: Offline image viewing

Scaling Considerations:

  • 10K users: Single server SSR works
  • 1M users:
    • Edge SSR (Vercel, Cloudflare)
    • Separate API gateway
    • Image processing service
  • 10M users:
    • Feed sharding by user
    • Read replicas
    • Micro-frontends for features

Example 2: Design a Collaborative Document Editor (Google Docs-like)​

Clarification:

  • Real-time collaboration required? (Yes)
  • Simultaneous editors expected? (Up to 50)
  • Mobile support? (Yes)
  • Offline editing? (Nice to have)

High-level Design:

Architecture:
β”œβ”€ Rendering: CSR (no SEO need, auth-gated)
β”œβ”€ Real-time: WebSocket with CRDT for conflict resolution
β”œβ”€ State:
β”‚ β”œβ”€ Local: Prosemirror/Quill editor state
β”‚ └─ Sync: Yjs for distributed state
β”œβ”€ Persistence:
β”‚ β”œβ”€ Auto-save every 2s (debounced)
β”‚ └─ Manual save option
└─ Offline: IndexedDB + sync on reconnect

Key Decisions:

  1. CSR Only

    • Why: Auth-gated, no SEO needed, heavy interactivity
    • Trade-off: Slower initial load OK for tool
    • Alternative: Could SSR shell for faster perceived load
  2. CRDT for Conflict Resolution

    • Why: Automatic merge of concurrent edits
    • Options: Yjs (recommended), Automerge, operational transforms
    • Trade-off: Complexity vs. robust collaboration
    • Alternative: Last-write-wins (simpler but loses data)
  3. WebSocket over Polling

    • Why: Low latency, bidirectional
    • Trade-off: Infrastructure complexity, connection management
    • Fallback: Long polling for old browsers
  4. Editor Choice: Prosemirror

    • Why: Flexible, powerful, collaborative-ready
    • Trade-off: Steeper learning curve vs. Draft.js/Quill
    • Alternative: Quill (simpler, less flexible)
  5. Optimistic Updates + Rollback

    • Why: Instant typing feedback
    • Implementation:
      • Apply change locally immediately
      • Send to server
      • Rollback if conflict/error
  6. Cursor Positioning

    • Show other users' cursors with names/colors
    • Implementation: Relative positioning in CRDT
    • Challenge: Performance with 50 users (throttle updates)

Performance Considerations:

  • Document Size:

    • Paginate very long docs (100+ pages)
    • Lazy load images/embeds
    • Virtual scrolling for large docs
  • Collaboration Scale:

    • Up to 10 users: Direct WebSocket
    • 10-50 users: Throttle cursor updates (200ms)
    • 50+ users: Consider room-based splitting
  • Memory Management:

    • Cleanup old history (keep 100 operations)
    • Garbage collect CRDT tombstones
    • Unload off-screen content

Offline Strategy:

  • IndexedDB stores document + pending changes
  • Service Worker caches app shell
  • Sync queue when reconnecting
  • Conflict resolution UI if diverged

Example 3: Design an E-commerce Product Listing Page​

Requirements:

  • 10K products, need filters/search
  • SEO critical
  • Fast perceived performance
  • Mobile-first

High-level Design:

Architecture:
β”œβ”€ Rendering: ISR (Next.js)
β”‚ β”œβ”€ Static generation for popular products
β”‚ └─ On-demand for long tail
β”œβ”€ Search: Algolia/Elasticsearch
β”œβ”€ Filters: URL state + React Query
└─ Images: CDN + progressive loading

Key Decisions:

  1. ISR over SSR/SSG

    • Why:
      • SEO (need server rendering)
      • Fresh inventory (revalidate every 5 min)
      • Scale (10K builds too slow for pure SSG)
    • Trade-off: Next.js lock-in
    • Alternative: SSR + aggressive CDN caching
  2. Search: Algolia (managed) vs Elasticsearch (self-hosted)

    • Algolia Pros:
      • Fast setup
      • Great DX
      • Built-in typo tolerance
    • Algolia Cons:
      • Expensive at scale
      • Vendor lock-in
    • When to switch: Over 1M searches/month β†’ consider Elasticsearch
  3. Filter State in URL

    • Why: Shareable links, back button works
    • Implementation: URLSearchParams + React Router
    • Trade-off: URL can get ugly with many filters
  4. Virtualization for Long Lists

    • Why: 1000+ products per page possible
    • Implementation: react-window
    • Alternative: Pagination (simpler, SEO-friendly)
    • Decision: Use pagination with "Load More" for SEO
  5. Image Strategy

    • Blur placeholder (LQIP)
    • Lazy load (Intersection Observer)
    • Responsive images
    • WebP with JPEG fallback
    • CDN with automatic optimization (Cloudinary)

Performance Budget:

  • LCP < 2.5s (hero image)
  • FID < 100ms
  • CLS < 0.1 (reserve image space)

Caching Strategy:

  • ISR: Revalidate every 5 min
  • CDN: Cache static assets 1 year
  • Browser: Cache product images 1 week
  • API: React Query cache 5 min, stale-while-revalidate

Mobile Optimizations:

  • Sticky filters button (mobile)
  • Bottom sheet for filters (not sidebar)
  • Touch-friendly product cards (min 44px)
  • Reduce image quality on slow connections

Key Takeaways​

Universal Principles​

  1. No Silver Bullets: Every decision trades one benefit for another.

  2. Start Simple: Complexity should be justified by requirements, not resume building.

  3. Measure First: Don't optimize what you can't measure.

  4. User-Centric: Performance metrics exist to serve user experience.

  5. Evolutionary Architecture: Design for change, not perfection.

Interview Success Formula​

Great Answer = Clear Communication
+ Trade-off Awareness
+ Justification
+ Adaptability

Remember:

  • Interviewers want to see your thinking process, not just the answer
  • There's rarely one "correct" solution
  • Asking clarifying questions shows experience
  • Acknowledging limitations shows maturity
  • Discussing when you'd change approaches shows depth

Red Flags to Avoid​

❌ "We should use microservices/GraphQL/etc." (without justification) ❌ "This is the best way to do it" (no trade-off awareness) ❌ Over-engineering for small scale ❌ Ignoring non-functional requirements (security, a11y) ❌ Not considering costs (infrastructure, maintenance, developer time)

Green Flags to Show​

βœ… Ask clarifying questions first βœ… Start with simple solution, then iterate βœ… Mention trade-offs for every decision βœ… Consider different scales (10K vs 1M vs 10M users) βœ… Think about maintenance and team velocity βœ… Consider total cost of ownership βœ… Show awareness of modern best practices βœ… Be honest about what you don't know


Quick Reference Cards​

When to Use What​

Rendering:

  • CSR: Dashboards, auth-gated tools
  • SSR: E-commerce, social media, content
  • SSG: Blogs, docs, marketing
  • ISR: Product catalogs, news sites

State Management:

  • Local: UI toggles, forms
  • Context: Theme, i18n, auth status
  • React Query/SWR: Server data
  • Redux/Zustand: Complex business logic

Data Fetching:

  • REST: Default choice, simple CRUD
  • GraphQL: Complex nested data, mobile apps
  • tRPC: Full-stack TypeScript monorepos

Styling:

  • Tailwind: Fast development, consistency
  • CSS Modules: Component libraries
  • CSS-in-JS: Heavy theming needs
  • Plain CSS: Simple sites, performance-critical

Performance Quick Wins​

  1. Images: WebP, lazy load, responsive srcset
  2. Fonts: System fonts or subset web fonts
  3. Code Splitting: Route-based, dynamic imports
  4. Compression: Enable Gzip/Brotli
  5. Caching: HTTP headers, CDN, React Query
  6. Bundle: Tree shaking, minification
  7. Critical CSS: Inline above-fold styles
  8. Preload: Critical resources

Common Interview Questions​

  1. "Design a news feed (Twitter/Instagram/Facebook)"
  2. "Design a real-time collaborative editor (Google Docs)"
  3. "Design a video streaming platform (YouTube)"
  4. "Design an e-commerce site (Amazon)"
  5. "Design a chat application (WhatsApp/Slack)"
  6. "Design a file storage system (Dropbox)"
  7. "Design a dashboard with real-time data"
  8. "Design a booking system (Airbnb)"

For each, remember to discuss:

  • Rendering strategy
  • State management
  • Real-time needs (if any)
  • Caching strategy
  • Performance considerations
  • Scaling approach

Additional Resources​

Further Reading​

  • Performance: web.dev, WebPageTest
  • React Patterns: patterns.dev
  • System Design: Front-End Engineer (book)
  • Best Practices: MDN, React docs

Practice Platforms​

  • Frontend Mentor (UI challenges)
  • GreatFrontEnd (system design questions)
  • LeetCode (algorithmic problems)
  • Pramp/Interviewing.io (mock interviews)

Final Note: This guide is a reference, not a script. Use it to develop intuition about trade-offs, then adapt to each unique situation. The best engineers don't memorize solutionsβ€”they understand principles and apply them contextually.

Good luck with your interviews! πŸš€